/** @file         demo.c
 *  @brief        使用范例
 *  @author       Schips
 *  @date         2020-10-27 22:12:43
 *  @version      v1.0
 *  @copyright    Copyright By Schips, All Rights Reserved
 *
 **********************************************************
 *
 *  @par 修改日志:
 *  <table>
 *  <tr><th>Date       <th>Version   <th>Author    <th>Description
 *  <tr><td>2020-10-27 <td>1.0       <td>Schips    <td>创建初始版本
 *  </table>
 *
 **********************************************************
 */

#include <stdio.h>
#include <string.h>

#include "ring_buffer_memory_pool.h"

#define FIFO_MEM_SIZE  102400
static char buffer_for_fifo[FIFO_MEM_SIZE];
static char buffer_for_fifo2[FIFO_MEM_SIZE];

void test1(void);
void test2(void);
void test3(void);
void test4(void);

int main(int argc, char *argv[])
{
    test1();
    test2();
    test3();
    test4();
}

void test1(void)
{
    int id;
    unsigned int cnt;
    char *pa, *pb;
    char *rpa, *rpb;

    printf("==================\n");
    printf("\n\n单个池的使用\n");

    // 初始化，并返回最大的池数
    cnt = rbmp_init();
    printf("Max pool cnt is %d\n", cnt);

    // 添加 内存池
    rbmp_add_pool("No1", buffer_for_fifo,  sizeof(buffer_for_fifo));

    // 打印 所有 池 的信息
    rbmp_dump();

    // 申请内存
    pa = rbmp_malloc_by_name("No1", 100);
    printf("%p\n", pa);

    if(pa)
        memset(pa, 0x5a, 100);
    // 待会能够看到打印的信息
    rbmp_dump();

    // 获取 之前申请的内存, 内存大小放置于 cnt 中
    pb = rbmp_get_first(&cnt);

    // 打印结果，符合预期
    printf("get_first : size [%d] , addr %p %p, same %d\n", cnt, pa, pb, pa == pb );

    // 根据不同的获取方式，都能得到同一个pool中的内存
    id = rbmp_get_pool_id("No1");
    rpa = rbmp_get_first_by_id(id, &cnt);

    rpb = rbmp_get_first_by_name("No1", &cnt);
    printf("get_first : addr %p %p, same %d\n", rpa, rpb, rpa == rpb );

    // 释放
    rbmp_free_first();
    // 由于只 malloc 了一次，所以pb = NULL
    pb = rbmp_get_first(&cnt);
    printf("[%d] %p %p %d\n", cnt, pa, pb, pa == pb );

    // 删除池
    rbmp_remove_pool("No1");
    // 再次打印
    rbmp_dump();

}

void test2(void)
{
    int id;
    unsigned int cnt;
    char *pa, *pb;
    char *rpa, *rpb;

    printf("==================\n");
    printf("\n\n多个池的使用\n");

    // 同样是初始化
    cnt = rbmp_init();
    printf("Max pool cnt is %d\n", cnt);

    // 这次多申请一个池
    rbmp_add_pool("No1", buffer_for_fifo,  sizeof(buffer_for_fifo));
    rbmp_add_pool("No2", buffer_for_fifo2, sizeof(buffer_for_fifo2));
    rbmp_dump();

    // 由于现在有多个池，可以使用名字或ID进行区分，以在对应的pool中获取内存。
    pa = rbmp_malloc_by_name("No1", 100);
    printf("%p\n", pa);
    pb = rbmp_malloc_by_name("No2", 100);
    printf("%p\n", pb);
    //pa = rbmp_malloc(100);
    if(pa)
        memset(pa, 0xff, 100);
    rbmp_dump();

    // 不指定name或id 时，所有的操作都是以 第一个池 为默认的
    rpa = rbmp_get_first(&cnt); // No1

    id = rbmp_get_pool_id("No2");
    rpb = rbmp_get_first_by_id(id, &cnt);
    // 肯定不一样
    printf("get_first : addr %p %p, diff %d\n", rpa, rpb, rpa == rpb );

    rbmp_free_first(); // No1

    pb = rbmp_get_first_by_id(id, &cnt);
    printf("[%d] %p %p %d\n", cnt, pa, pb, pa == pb );

    // 删除所有池
    rbmp_remove_all_pools();
    rbmp_dump();

}

void test3(void)
{
    int ret;
    int cnt;
    // 简单的测试
    char *pa, *pb, *pc;
    unsigned int size;
    // 初始化
    cnt = rbmp_init();
    printf("Max pool cnt is %d\n", cnt);
    // 注册一个块
    ret = rbmp_add_pool("test", buffer_for_fifo, sizeof(buffer_for_fifo));
    printf("rbmp_init %d (with buffer %p)\n", ret, buffer_for_fifo);
    // 申请
    pa = rbmp_malloc(6);
    printf("rbmp_malloc %p size 6\n", pa);
    memset(pa, ret, 6);
    rbmp_dump();

    // 申请
    pb = rbmp_malloc(15);
    printf("rbmp_malloc %p size 15\n", pb);
    memset(pb, ret+1, 15);
    rbmp_dump();

    // 获取第一个内存块节点
    printf("*****************************\n");
    printf("*****************************\n");
    if(pa == rbmp_get_first(&size))
    {
        printf("rbmp_get_first and yes, %p with size %d\n", pa, size);
        // 打印
        printf("rbmp_dump , block cnt should be 2\n");
        rbmp_dump();
        // 释放
        rbmp_free_first();
        printf("rbmp_dump , block cnt should be 1\n");
        rbmp_dump();
    }else {
        printf("Error\n");
    }
    printf("*****************************\n");
    // 获取第二个内存块节点
    if(pb == rbmp_get_first(&size))
    {
        printf("rbmp_get_first and yes, %p with size %d\n", pb, size);
        // 打印
        printf("rbmp_dump , block cnt should be 1\n");
        rbmp_dump();
        // 释放
        rbmp_free_first();
        printf("rbmp_dump , block cnt should be 0\n");
    }else {
        printf("Error\n");
    }

    // 获取，但无效
    printf("*****************************\n");
    pc = rbmp_get_first(&size);
    if(pa != pc) // 此时应该返回空
    {
        printf("rbmp_get_first and will be null, %p(0) with size %d\n", pc, size);
        rbmp_dump();
    }else {
        printf("Error\n");
    }
    rbmp_remove_all_pools();
}

void test4(void)
{
    // 针对 批量申请释放的测试
    int ret;
    int i;
    int id1, id2;
    char *p_array1[100];
    char *p_array2[100];
    unsigned int size_array1[100];
    unsigned int size_array2[100];
    
    // 初始化
    rbmp_init();
    ret = rbmp_add_pool("bat", buffer_for_fifo,  sizeof(buffer_for_fifo));
    ret = rbmp_add_pool("bat2",  buffer_for_fifo2, sizeof(buffer_for_fifo2));
    printf("fifo_init ret is %d (with buffer %p)\n", ret, buffer_for_fifo);

    // 取各内存池ID，（用于快速申请、释放, 比 by_name 快）
    id1 = rbmp_get_pool_id("bat");
    id2 = rbmp_get_pool_id("bat2");

    for (i = 0; i < 100; ++i) {
        // 申请内存
        p_array1[i] = rbmp_malloc_by_id(id1, 1000);
        p_array2[i] = rbmp_malloc_by_id(id2, 1000);
        printf("[%d] rbmp_malloc %p size 1000\n", i, p_array1[i]);
        printf("[%d] rbmp_malloc %p size 1000\n", i, p_array2[i]);
        if(p_array1[i] == p_array2[i])
        {
            // 申请的地址不可能重复
            printf("Error !\n");
            return ;
        }
        memset(p_array1[i], i, 1000);
        memset(p_array2[i], i, 1000);
    }
    rbmp_dump();

    for (i = 0; i < 100; ++i) {
        // 获取、并释放
        if(p_array1[i] == rbmp_get_first_by_id(id1, &size_array1[i]))
        {
            rbmp_free_first_by_id(id1);
        }else
        {
            printf("rbmp_get_first err!\n");
            return;
        }

        if(p_array2[i] == rbmp_get_first_by_id(id2, &size_array2[i]))
        {
            rbmp_free_first_by_id(id2);
        }else
        {
            printf("rbmp_get_first err!\n");
            return;
        }
    }

    rbmp_dump();
}

